'''
Copyright 2011 Jake Ross

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
#============= enthought library imports =======================
from traits.api import  Str, Int, Instance, Bool, Property, Event, Button, String
from traitsui.api import View, Item, Group, HGroup, VGroup, \
    ButtonEditor, Handler
from pyface.timer.api import Timer
#============= standard library imports ========================
import threading
import datetime
import select
import time
#============= local library imports  ==========================
from src.config_loadable import ConfigLoadable
#from handlers.api import TCPHandler, UDPHandler


#from src.managers.displays.messaging_display import MessagingDisplay
from src.led.led_editor import LEDEditor
from src.led.led import LED
from src.messaging.command_repeater import CommandRepeater
from src.helpers.datetime_tools import diff_timestamp
class RCSHandler(Handler):
    def init(self, info):
        '''
        '''
        obj = info.object
        if obj._running:
            obj.led.state = 2
    def object__running_changed(self, info):
        '''
           
        '''
        if info.initialized:
            obj = info.object
            if obj._running:
                obj.led.state = 2
            else:
                obj.led.state = 0

class RemoteCommandServer(ConfigLoadable):
    '''
    '''
    simulation = False
    _server = None
    repeater = Instance(CommandRepeater)

    host = Str(enter_set=True, auto_set=False)
    port = Int(enter_set=True, auto_set=False)
    klass = Str

    loaded_port = None
    loaded_host = None

    packets_received = Int
    packets_sent = Int
    repeater_fails = Int

    cur_rpacket = String
    cur_spacket = String

    server_button = Event
    server_label = Property(depends_on='_running')
    _running = Bool(False)
    _connected = Bool(False)

    save = Button
    _dirty = Bool(False)

    run_time = Str
    led = Instance(LED, ())

    def _repeater_default(self):
        '''
        '''

        c = CommandRepeater(
                            logger_name='{}_repeater'.format(self.name),
                            name=self.name,
                               configuration_dir_name='servers')
        c.bootstrap()
        return c

    def _repeater_fails_changed(self, old, new):
        if new != 0:
            self.repeater.led.state = 0

    def load(self, *args, **kw):
        '''
        '''

        config = self.get_configuration()
        if config:

            host = self.config_get(config, 'General', 'host')

            port = self.config_get(config, 'General', 'port', cast='int')
            if host is None or port is None:
                self.warning('Host and Port not set')
                return

            if port < 1024:
                self.warning('Port Numbers < 1024 not allowed')
                return

            server_class = self.config_get(config, 'General', 'class')
            if server_class is None:
                return
            self.klass = server_class[:3]

            ds = None
            if config.has_option('Requests', 'datasize'):
                ds = config.getint('Requests', 'datasize')

            ptype = self.config_get(config, 'Requests', 'type', optional=False)
            if ptype is None:
                return

            self.datasize = ds
            self.processor_type = ptype

            addr = (host, port)
            self.host = host
            self.port = port

            self.loaded_host = host
            self.loaded_port = port

            self._server = self.server_factory(server_class, addr, ptype, ds)

            #add links
            for link in self.config_get_options(config, 'Links'):
                #note links cannot be stopped 
                self._server.add_link(link,
                                       self.config_get(config, 'Links', link))

            if self._server is not None and self._server.connected:
                saddr = '(%s,%s)' % self._server.server_address
                msg = '%s - %s' % (server_class, saddr)
                self.info(msg)
                self._connected = True
                return True
            else:
                self._connected = False
                self.warning('Cannot connect to %s: %s' % addr)


    def server_factory(self, klass, addr, ptype, ds):
        '''
        '''
        #from tcp_server import TCPServer
        #from udp_server import UDPServer

        module = __import__('src.messaging.{}_server'.format(klass[:3].lower()), fromlist=[klass])
        factory = getattr(module, klass)

#        gdict = globals()
#        if handler in gdict:
#            handler_klass = gdict[handler]

#        server = gdict[server_class]
        if ds is None:
            ds = 2 ** 10
#        return server(self, ptype, ds, addr, handler_klass)
        return factory(self, ptype, ds, addr)

    def open(self):
        '''
        '''
        self._running = True
        #t = threading.Thread(target = self._server.serve_forever)
        t = threading.Thread(target=self.start_server)
        t.start()

        return True

    def start_server(self):
        SELECT_TIMEOUT = 1
#        THREAD_LIMIT = 15
        while self._running:
            try:
                readySocket = select.select([self._server.socket], [],
                                            [], SELECT_TIMEOUT)
                if readySocket[0]:
                    self._server.handle_request()
#                    if threading.activeCount() < THREAD_LIMIT:
#                        self._server.handle_request()

            except:
                pass
#        self._server.socket.close()

    def shutdown(self):
        '''
        '''
        self._connected = False
        if self._server is not None:
#            self._server.shutdown()
            self._server.socket.close()

            self._running = False

    def traits_view(self):
        '''
        '''
        cparams = VGroup(
                        HGroup(
                                Item('led', show_label=False,
                                     editor=LEDEditor()),
                                Item('server_button', show_label=False,
                                     editor=ButtonEditor(label_value='server_label'),
                                     enabled_when='_connected'),
                                ),

                        Item('host', visible_when='not _running'),
                        Item('port', visible_when='not _running'),

                        show_border=True,
                        label='Connection',
                        )
        stats = Group(
                      Item('packets_received', style='readonly'),
                      Item('cur_rpacket', label='Recieved', style='readonly'),
                      Item('packets_sent', style='readonly'),
                      Item('cur_spacket', label='Sent', style='readonly'),

                      Item('repeater_fails', style='readonly'),
                      Item('run_time', style='readonly'),
                      show_border=True,
                      label='Statistics',
                      visible_when='_connected'
                      )

        buttons = HGroup(
                         Item('save', show_label=False, enabled_when='_dirty')
                         )
        v = View(VGroup(
                        cparams,
                        stats,
                        buttons
                        ),
                handler=RCSHandler,
               )
        return v

    def _run_time_update(self):
        '''
        '''

#        t = datetime.datetime.now() - self.start_time

#        h = t.seconds / 3600
#        m = (t.seconds % 3600) / 60
#        s = (t.seconds % 3600) % 60

        t, h, m, s = diff_timestamp(datetime.datetime.now(), self.start_time)


        rt = '{:02n}:{:02n}:{:02n}'.format(h, m, s)
        if t.days:
            rt = '{} {:02n}:{:02n}:{:02n}' .format(t.days, h, m, s)
        self.run_time = rt

    def __running_changed(self):
        '''
        '''
        if self._running:
            self.start_time = datetime.datetime.now()
            self.timer = Timer(1000, self._run_time_update)
        else:
            self.timer.Stop()

    def _anytrait_changed(self, name, value):
        '''

        '''
        if name in ['host', 'port']:
            attr = 'loaded_{}'.format(name)
            a = getattr(self, attr)
            if value != a and a is not None:
                self._dirty = True

    def _save_fired(self):
        '''
        '''

        self.shutdown()
        config = self.get_configuration()
        for attr in ['host', 'port']:
            a = getattr(self, attr)
            setattr(self, 'loaded_{}'.format(attr), a)
            config.set('General', attr, a)
            self.write_configuration(config)
            self.load()
        self._dirty = False

    def _server_button_fired(self):
        '''
        '''
        if self._running:
            self.shutdown()
        else:
            #reset the stats
            self.packets_received = 0
            self.packets_sent = 0
            self.cur_rpacket = ''
            self.cur_spacket = ''
            self.repeater_fails = 0

#            self._server = self.server_factory('TCPServer',
#                                               (self.host, self.port),
#                                               self.handler,
#                                               self.processor_type,
#                                               self.datasize
#                                             )
#            self.open()
            self.bootstrap()

    def _get_server_label(self):
        '''
        '''
        return 'Start' if not self._running else 'Stop'

#============= EOF ====================================

#            if self._server is not None:
#                sa = self._server.server_address
#                '''
#                    BUG 
#                    1. start _server with 129.138.12.141 
#                        _server responds to commands sent to 129.138.12.141
#                        
#                    2. reinitialize _server with 129.138.12.140
#                        _server still responds to commands sent to 129.138.141
#                '''
#                if sa != addr:
#                    
#                    
#                    self.warning('Reinitialization of _server not allowed- restart program to alter _server parameters')
#            else:
